#ifndef _NODE_H
#define _NODE_H

#include "str.h"
#include <vector>
#include <string>
#include <sstream>

using namespace std;

class LiteralValue {

public:

    int intValue;
    double doubleValue;
    string strValue;
    string type;

    LiteralValue(int intVar, string stringValue, string kind) {
        strValue = stringValue;
        intValue = intVar;
        type = kind;
    }

    LiteralValue(double _doubleValue, string kind) {
        doubleValue = _doubleValue;
        ostringstream stm;
        stm << doubleValue;
        strValue = stm.str();
        type = kind;
    }

    ~LiteralValue() {

    }

};

class TableStmt {

public:
    TableStmt(string name, vector<string> attrNameList_, bool all_)
        : tableName(name)
        , attrNameList(attrNameList_)
        , all(all_)
    {
        if(all) {

            return;
        }
    }

    TableStmt(string name, bool all_)
        : tableName(name)
        , all(all_)
    {
    }
    ~TableStmt() {

    }

    string tableName;
    bool all;
    vector<string> attrNameList;
};

class InsertStmt {

public:

    TableStmt* table;
    vector< vector<LiteralValue*> > attrValueList;
    vector< vector<string> > segments;
    InsertStmt(TableStmt* tableStmt, vector< vector<LiteralValue*> > attrValueList_ )
        : table(tableStmt)
        , attrValueList(attrValueList_) {
            for(int i = 0; i < attrValueList.size(); i++) {
                vector<string> temp;

                for(int j = 0; j < attrValueList[i].size(); j++) {
                    string a = attrValueList[i][j]->strValue;
                    temp.push_back(attrValueList[i][j]->strValue);
                }
                segments.push_back(temp);
            }
    }

    ~InsertStmt() {
        for(int i = 0; i < attrValueList.size(); i++) {
            for(int j = 0; j < attrValueList[i].size(); j++) {
                delete attrValueList[i][j];
            }
        }
        delete table;
    }

};

class PrimaryKey {
public:
    PrimaryKey(string _columnName) {
        columnName = _columnName;
    }

    string columnName;
};

class ColumnType {

public:
    ColumnType(int _size, string kind) {
        type = kind;    size = _size;
    }

    ColumnType(string kind) {
        type = kind;
        size = 0;
    }

    string type;
    int size;
};

class ColumnDec {

public:
    ColumnDec(string ColumnName, ColumnType* _columnType, bool _NotNull)
        : columnName(ColumnName)
        , columnType(_columnType)
        , NotNull(_NotNull)
    {
    }

    ~ColumnDec() {
        delete columnType;
    }

    string columnName;
    ColumnType* columnType;
    bool NotNull;
};

class AggregateFunction {

public:
    string aggreType;
    string attrName;

    AggregateFunction(string _aggreType, string _attrName)
        : aggreType(_aggreType)
        , attrName(_attrName)
    {}

    string toString() {
        return aggreType + "(" + attrName +")";
    }
};

//*******WhereClause******
class AttrExpr {

public:
    string tableName;
    string attrName;
    AggregateFunction* aggregateFunc;

    AttrExpr(string _tableName, string _attrName)
        : tableName(_tableName)
        , attrName(_attrName)
    {
        aggregateFunc = NULL;
    }

    AttrExpr(string _attrName)
        : tableName("")
        , attrName(_attrName)
    {
        aggregateFunc = NULL;
    }

    AttrExpr(AggregateFunction* _aggregateFunc)
        : aggregateFunc(_aggregateFunc)
    {
        tableName = "";
        attrName = _aggregateFunc->attrName;
    }

    string toString() {
        if(tableName == "") {
            if(aggregateFunc == NULL)
                return attrName;
            else
                return aggregateFunc->aggreType + "(" + aggregateFunc->attrName + ")";
        } else {
            return tableName + "." + attrName;
        }
    }

    ~AttrExpr() {
        if(aggregateFunc != NULL)
            delete aggregateFunc;
    }
};

class ValueExpr {

public:
    AttrExpr* attrExpr;
    int intValue;
    string strValue;
    double doubleValue;
    string type;

    ValueExpr(int _intValue, string kind)
        : intValue(_intValue)
        , type(kind)
    {

    }

    ValueExpr(double _doubleValue, string kind)
        : doubleValue(_doubleValue)
        , type(kind)
    {
    }

    ValueExpr(string _strValue, string kind)
        : strValue(_strValue)
        , type(kind)
    {

    }

    ValueExpr(AttrExpr* _attrExpr, string kind)
        : attrExpr(_attrExpr)
        , type(kind)
    {

    }

    ~ValueExpr() {
        if(type == "attrExpr")
            delete attrExpr;
    }

    string toString() {
        if(type == "attrExpr") {
            return attrExpr->toString();
        } else if(type == "int") {
            stringstream ss;
            ss << intValue;
            string str = ss.str();
            return str;
        } else if(type == "string") {
            return strValue;
        }
    }

};

class BoolExpr {

public:
    AttrExpr* attrExpr;
    int compareOp;
    ValueExpr* valueExpr;
    string type;
    string match;

    BoolExpr(AttrExpr* _attrExpr, int _compareOp, ValueExpr* _valueExpr)
        : attrExpr(_attrExpr)
        , compareOp(_compareOp)
        , valueExpr(_valueExpr)
    {
        type = "";
    }

    BoolExpr(AttrExpr* _attrExpr, string _type, string _match)
        : attrExpr(_attrExpr)
        , type(_type)
        , match(_match)
    {
        compareOp = 0;
        valueExpr = NULL;
    }

    BoolExpr(AttrExpr* _attrExpr, string kind)
        : attrExpr(_attrExpr)
        , type(kind)
    {
        compareOp = 0;
        valueExpr = NULL;
    }

    string toString() {
        stringstream ss;
        ss << compareOp;
        string str = ss.str();
        return attrExpr->toString() + str + valueExpr->toString();
    }

    bool res(string leftValue, string rightValue, int type) {
        if(type == 0) {
            istringstream buffer(leftValue);
            double intValue;
            buffer >> intValue;

            istringstream buffer1(rightValue);
            double rightInt;
            buffer1 >> rightInt;

            switch(compareOp) {
                case '=':
                    return intValue == rightInt;
                    break;

                case '>':
                    return intValue > rightInt;
                    break;

                case '<':
                    return intValue < rightInt;
                    break;

                case '>'+'=':
                    return intValue >= rightInt;
                    break;

                case '<'+'=':
                    return intValue <= rightInt;
                    break;

                default:
                    break;
            }

        } else {
            switch(compareOp) {
                case '=':
                    return leftValue == rightValue;
                    break;

                case '>':
                    return leftValue > rightValue;
                    break;

                case '<':
                    return leftValue < rightValue;
                    break;

                case '>'+'=':
                    return leftValue >= rightValue;
                    break;

                case '<'+'=':
                    return leftValue <= rightValue;
                    break;

                default:
                    break;
            }
        }
    }

    bool res(string value) {
        if(compareOp == 0) {
            if(type == "null") {
                return (value == "NULL") || (value == "null");
            } else if(type == "notNull"){
                return (value != "NULL") && (value != "null");
            } else if(type == "LIKE") {
                return Str::match(match, value);
            }
        } else {
            if(valueExpr->type == "string") {
                switch(compareOp) {
                    case '=':
                        return value == valueExpr->strValue;
                        break;

                    case '>':
                        return value > valueExpr->strValue;
                        break;

                    case '<':
                        return value < valueExpr->strValue;
                        break;

                    case '>'+'=':
                        return value >= valueExpr->strValue;
                        break;

                    case '<'+'=':
                        return value <= valueExpr->strValue;
                        break;

                    case '!'+'=':
                        return value != valueExpr->strValue;
                        break;

                    default:
                        break;
                }
                return value == valueExpr->strValue;
            } else if(valueExpr->type == "int") {
                istringstream buffer(value);
                int intValue;
                buffer >> intValue;

                int intValueE = valueExpr->intValue;

                switch(compareOp) {
                    case '=': {
                        return intValue == intValueE;
                        break;
                    }

                    case '>':
                        return intValue > intValueE;
                        break;

                    case '<':
                        return intValue < intValueE;
                        break;

                    case '>'+'=':
                        return intValue >= intValueE;
                        break;

                    case '<'+'=':
                        return intValue <= intValueE;
                        break;

                    case '!'+'=':
                        return intValue != intValueE;
                        break;

                    default:
                        break;

                }
            } else if(valueExpr->type == "double") {
                istringstream buffer(value);
                double intValue;
                buffer >> intValue;

                double intValueE = valueExpr->doubleValue;

                switch(compareOp) {
                    case '=': {
                        return intValue == intValueE;
                        break;
                    }

                    case '>':
                        return intValue > intValueE;
                        break;

                    case '<':
                        return intValue < intValueE;
                        break;

                    case '>'+'=':
                        return intValue >= intValueE;
                        break;

                    case '<'+'=':
                        return intValue <= intValueE;
                        break;

                    case '!'+'=':
                        return intValue != intValueE;
                        break;

                    default:
                        break;

                }

            }
        }
    }

    ~BoolExpr() {
        delete attrExpr;
        if(valueExpr != NULL)
            delete valueExpr;
    }

};

class WhereExpr {

public:
    vector<string> tableName;
    vector<BoolExpr*> whereClause;

    WhereExpr(vector<string> _tableName, vector<BoolExpr*> _whereClause)
        : tableName(_tableName)
        , whereClause(_whereClause)
    {
    }

    WhereExpr(vector<string> _tableName)
        : tableName(_tableName)
    {
    }

    ~WhereExpr() {
        for(int i = 0; i < whereClause.size(); i++)
            delete whereClause[i];
    }
};


//***********UpdateStmt**********
class SetStmt {
public:
    string attrName;
    string setExpr;

    SetStmt(string _attrName, string _setExpr)
        : attrName(_attrName)
        , setExpr(_setExpr)
    {
    }

};

#endif
